import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import java.util.StringTokenizer;


public class Asteroid extends MovingObject 
{
	private final static int SIZE_BIG = 24;
	private final static int SIZE_MED = 16;
	private final static int SIZE_SMALL = 10;
	
	public final static int POINTS = 5;
	
	public final static int MIN_ABS_SPEED = 15;
	
	protected int size; // radius of the asteroid's hitbox (image is a little bigger)
	private BufferedImage image;
		
	private Asteroid(int x, int y, int size)
	{
		super(x,y);
		this.size = size;
		
		drawImage();
		
		vx = 50 - 100*AsteroidsGame.rng.nextDouble(); // [-50, 50)
		vy = 50 - 100*AsteroidsGame.rng.nextDouble();
		
		if(Math.abs(vx) < MIN_ABS_SPEED)
			vx = Math.signum(vx)*MIN_ABS_SPEED;
		if(Math.abs(vy) < MIN_ABS_SPEED)
			vy = Math.signum(vy)*MIN_ABS_SPEED;
	}
	
	// create a default Asteroid
	public Asteroid(int x, int y)
	{
		this(x, y, SIZE_BIG);
	}
	
	// create an Asteroid based on the provided one:
	//  vx and xy similar to parent's vx and vy
	//  same x and y
	//  one size smaller
	private Asteroid(Asteroid parent)
	{
		super((int)parent.x, (int)parent.y);
		
		if(parent.size == SIZE_BIG)
			size = SIZE_MED;
		else if(parent.size == SIZE_MED)
			size = SIZE_SMALL;
		else // ???
		{
			System.err.printf("split() on asteroid size %d?\n", parent.size);
			size = SIZE_BIG;
		}
		drawImage();
		
		vx = parent.vx*2/3 + (40 - 80*AsteroidsGame.rng.nextDouble());
		vy = parent.vy*2/3 + (40 - 80*AsteroidsGame.rng.nextDouble());
		if(Math.abs(vx) < MIN_ABS_SPEED)
			vx = Math.signum(vx)*MIN_ABS_SPEED;
		if(Math.abs(vy) < MIN_ABS_SPEED)
			vy = Math.signum(vy)*MIN_ABS_SPEED;
	}
	
	public Asteroid(StringTokenizer strtok)
	{
		super();
		loadState(strtok);
		
		drawImage();
	}
	
	// Implements getImage of SpaceObject
	public BufferedImage getImage() { return image; }
	
	// Implements getWrapHeight and getWrapWidth of MovingObject
	public int getWrapWidth() { return size*5/2; } // this size does not include the tail
	public int getWrapHeight() { return size*5/2; }
	
	// Implement collision functions
	public CollisionType collisionType() { return CollisionType.CIRCLE; }
	public double[] collisionData()
	{
		// center + radius
		double[] circle = {x, y, size};
		return circle;
	}
	
	protected void loadState(StringTokenizer strtok) throws NumberFormatException
	{
		super.loadState(strtok);
		size = Integer.parseInt(strtok.nextToken());
	}
	protected String saveState()
	{
		return "Asteroid " + super.saveState() + String.format("%d\n", size);
	}
	
	private void drawImage()
	{
		image = new BufferedImage(size*3, size*3, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = image.createGraphics();
		Random rng = AsteroidsGame.rng;
		
		// draw an irregular, sort of circular object
		// by starting at a random angle, the moving around the circle, picking
		// a new random radius each time until a full circle has been drawn
		double startAngle = rng.nextDouble() * 2*Math.PI;
		double angle = startAngle;
		double r = 1*size;
		Polygon poly = new Polygon();
		while(angle - startAngle < 2*Math.PI)
		{
			poly.addPoint((int)(r*Math.cos(angle)), (int)(r*Math.sin(angle)));
			angle += Math.PI/16 + rng.nextDouble() * Math.PI/8;
			r = this.size * (rng.nextDouble() * 0.4 + 1);
		}
		
		// draw that polygon to the image
		g.translate(image.getWidth()/2, image.getHeight()/2); // center of image
		g.setColor(Color.WHITE);
		g.drawPolygon(poly);
		g.dispose();
	}

	// Implements hit() from SpaceObject
	// an asteroid can be hit by a Bullet or Spaceship
	public boolean hit(SpaceObject by)
	{
		if(by instanceof Bullet)
		{
			if(((Bullet)by).consumed)
				return false; // bullets can only hit one asteroid
			((Bullet)by).consumed = true;
			
			if(((Bullet)by).isShooter(AsteroidsGame.game.player1))
				AsteroidsGame.game.score(1, POINTS);
			if(((Bullet)by).isShooter(AsteroidsGame.game.player2))
				AsteroidsGame.game.score(2, POINTS);
		}
		else if(by instanceof Spaceship)
		{
			if(((Spaceship)by).isRogue()) // rogue spaceships have no effect on asteroids
				return false;
			// no points for destroying an asteroid with your face
		}
		
		split(); // make new smaller asteroids
		delete();
		
		// play explosion
		AsteroidsGame.soundManager.play(AsteroidsGame.asteroid_explosion);
		return true;
	}
	
	// generate new smaller asteroids based on the current one
	private void split()
	{
		if(size == SIZE_MED || size == SIZE_BIG)
		{
			for(int i = 0; i < 3; i++)
				AsteroidsGame.game.addObject(new Asteroid(this));
		}
	}
}
